Object tracking in video
import numpy as np
import argparse
import time
import cv2
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video",
help = "path to the (optional) video file")
args = vars(ap.parse_args())
# define the upper and lower boundaries for a color
# to be considered "blue"
blueLower = np.array([100,67,0],dtype="uint8")
blueUpper = np.array([255,128,50],dtype="uint8")
# load the video
if not args.get("video"):
camera = cv2.VideoCapture(0)
else:
camera = cv2.VideoCapture(args["video"])
我们将使用NumPy进行数值处理,使用argparse解析命令行参数,使用cv2进行OpenCV绑定。time包是可选的。
我们只需要一个命令行参数,–video,也就是我们视频的路径。
我们将在视频中追踪的对象是蓝色物体。由于除了该物体外,蓝色在视频中的任何其他位置都不常见,因此我们希望跟踪蓝色阴影。为了完成这种颜色跟踪,我们定义了蓝色阴影的下限和上限。请记住,OpenCV表示RGB颜色空间中的像素,但顺序相反。
在这种情况下,如果大于R=0,G=67,B=100且小于R=50,G=128,B=255,则将颜色定义为“蓝色”。
最后,我们打开视频文件并使用cv2.VideoCapture函数获取对它的引用。我们将此引用赋值给变量camera。
# keep looping
while True:
# grab the current frame
(grabbed,frame) = camera.read()
# check to see if we have reached the end of the video
if args.get("video") and not grabbed:
break
# determine which pixels fall within the blue boundaries
# and then blur the binary image
blue = cv2.inRange(frame,blueLower,blueUpper)
blue = cv2.GaussianBlur(blue,(3,3),0)
现在我们有了对视频的引用,便可以开始处理帧。
我们开始循环遍历帧,一次一个。调用read()方法的调用抓取视频中的下一帧,返回具有两个值的元组。第一个是grabbed,是一个布尔值,表示是否从视频文件中成功读取了帧。第二个frame,是帧本身。
然后,我们检查frame是否成功读取。如果未读取框架,则表示已到达视频的末尾,我们break掉while循环。
为了在frame中找到蓝色阴影,我们必须使用cv2.inRange函数。该函数有三个参数。第一个是我们想要检查的frame。第二个是RGB像素的lower threshold,第三个是上限阈值(upper threshold)。调用此函数的结果是阈值图像,像素落在上下范围内设置为白色,像素不属于此范围 设为黑色。
最后,我们对阈值图像进行高斯模糊处理,以使查找轮廓更准确。
# find contours in the image
(_,cnts,_) = cv2.findContours(blue.copy(),cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
# check to see if any contours were found
if len(cnts) > 0:
# sort the contours and find the largest one --
# we will assume this contour coorespondes to the
# area of my phone
cnt = sorted(cnts,key=cv2.contourArea,reverse=True)[0]
# compute the (rotated) bounding box around then
# contour and then draw it
rect = np.int32(cv2.boxPoints(cv2.minAreaRect(cnt)))
cv2.drawContours(frame,[rect],-1,(0,255,0),2)
# show the frame and the binary image
cv2.imshow("Traccking",frame)
cv2.imshow("Binary",blue)
# if your machine is fast, it may display the frames in
# what appears to be 'fast forward' since more than 32
# frames per second are being displayed -- a simple hack
# is just to sleep for a tiny bit in between frames;
# however, if your computer is slow, you probably want to
# comment out this line
time.sleep(0.025)
# if the 'q' key is pressed, stop the loop
if cv2.waitKey(1) & 0xFF == ord("q"):
break
# cleanup the camera and close any open windows
camera.release()
cv2.destroyAllWindows()
现在我们有了阈值图像,那么我们需要找到图像中最大的轮廓,假设最大轮廓对应于我们想要跟踪的蓝色物体轮廓。
我们调用cv2.findContours会在阈值图像中找到轮廓。我们使用copy()方法克隆阈值图像,因为cv2.findContour函数对传入的NumPy数组具有破坏性。
然后检查以确保实际发现轮廓。如果轮廓列表的长度为零,则没有找到蓝色区域。如果轮廓列表的长度大于零,那么我们需要找到最大的轮廓。这里,轮廓按相反的顺序排序(最大的第一个),使用cv2.contourArea函数来 计算轮廓的面积。具有较大区域的轮廓存储在列表的前面。在这种情况下,抓住具有最大面积的轮廓,再次假设该轮廓对应于蓝色物体的轮廓。
现在我们有了蓝色的轮廓,但我们需要在它周围绘制一个边界框。
调用cv2.minAreaRect计算轮廓周围的最小边界框。然后,cv2.boxPoints将边界框重新定义为点列表。
注意:在OpenCV 2.4.X中,我们将使用cv2.BoxPoints函数来计算轮廓的旋转边界框。但是,在OpenCV 3.0+中,此函数已移至cv2.boxPoints。两个函数执行相同的任务,只是略有不同的命名空间。
最后,我们使用cv2.drawContours函数绘制边界框。
具有检测到的蓝色物体的frame显示在第一个imshow,并且阈值图像(落入蓝色像素的下/上范围的像素)显示在第二个imshow。
上面,time.sleep(0.025)可选的。在许多较新型号的机器上,系统可能足够快以处理>32帧/秒。如果是这种情况,找到可接受的睡眠时间将减慢处理速度并将其降低到更正常的速度。
执行我们的脚本
python track.py
结果:

或者指定视频路径
python track.py --video "video\2018-11-27 18-38-15-927.mp4"
也是可以的。
完整代码:
链接:https://pan.baidu.com/s/1jvnoV_StHRTXlzK5Zvc3dw 提取码:q9bl
更多的参考:
Case Studies – Object Tracking in Video
Histogram of Oriented Gradients and Object Detection
;